home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
Storage.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-19
|
10KB
|
471 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "Storage.h"
#include "CLib.h"
#include "String.h"
#include "Error.h"
#include "Object.h"
#include "ObjectTable.h"
#include "Math.h"
#define MEM_MAGIC ((char)0xAB)
#define MEM_STAT
//#define MEM_CHECKOBJECTPOINTERS
#ifdef MEM_CHECKOBJECTPOINTERS
# define CheckObjPtr(name, p) ObjectTable::CheckPtrAndWarn(name, p);
#else
# define CheckObjPtr(name, p) p
#endif
const int cMemPoolSize = 100,
cObjMaxSize = 1024;
u_long Storage_lastobj, Storage_lastobjend;
bool Storage_proto;
static bool died;
static size_t maxA;
static FreeHookFun storageFreeHook;
static void *storageFreeHookData;
//---- Pool for a specific size ------------------------------------------------
struct FreeNode {
class FreeNode *next;
};
class Chunk {
public:
struct Chunk *next;
char *storage;
public:
Chunk(Chunk *n, size_t size)
{ next= n; storage= new char[size]; }
~Chunk()
{ SafeDelete(storage); }
};
class MemPool {
public:
friend class Storage;
struct Chunk *chunks;
struct FreeNode *freeList;
int lastIndex, chunkSize, allocated, recycled, freed;
size_t objSize;
public:
MemPool(size_t objSize);
~MemPool();
void *Alloc();
void Free(void *);
int nchunks();
};
static MemPool *pools[cObjMaxSize];
#ifdef MEM_STAT
static bool gMemStatistics;
static int ASizes[cObjMaxSize];
static int FSizes[cObjMaxSize];
static int totalA, totalF;
static void *ttt[1000];
static int tt, mem_size= -1, mem_ix= -1;
void EnterStat(size_t size, void *p)
{
if (gMemStatistics && size == mem_size) {
if (tt == mem_ix)
CLib::Abort();
ttt[tt++]= p;
}
maxA= Math::Max(maxA, size);
if (size >= cObjMaxSize)
ASizes[cObjMaxSize-1]++;
else
ASizes[size]++;
totalA+= size;
}
void RemoveStat(size_t size, void *vp)
{
if (gMemStatistics && size == mem_size) {
for (int i= 0; i < tt; i++)
if (ttt[i] == vp) {
ttt[i]= 0;
break;
}
}
if (size >= cObjMaxSize)
FSizes[cObjMaxSize-1]++;
else
FSizes[size]++;
totalF+= size;
}
#else
# define EnterStat(s, p) maxA= Math::Max(maxA, s);
# define RemoveStat(s, p)
#endif
static bool FreeFromPool(void *vp)
{
register int i;
register Chunk *p;
register MemPool *mp;
for (i= 0; i < cObjMaxSize; i++) {
if (mp= pools[i]) {
for (p= mp->chunks; p; p= p->next) {
if (vp >= (void*)p->storage
&& vp < (void*)(p->storage + mp->chunkSize)) {
mp->Free(vp);
return TRUE;
}
}
}
}
return FALSE;
}
/*
inline size_t storage_size(char *ptr)
{
return ((int*)ptr)[-1];
}
*/
#define storage_size(ptr) ((size_t)(((int*)ptr)[-1]))
//---- Pool for a specific size ------------------------------------------------
MemPool::MemPool(size_t osize)
{
objSize= osize;
chunkSize= cMemPoolSize * objSize;
chunks= 0;
lastIndex= cMemPoolSize; // force allocation of a new chunk
freeList= 0;
allocated= recycled= freed= 0;
}
MemPool::~MemPool()
{
Chunk *p, *lp;
for (p= chunks; p; p= lp) {
lp= p->next;
delete p;
}
}
int MemPool::nchunks()
{
int n;
Chunk *p;
for (n= 0, p= chunks; p; p= p->next, n++)
;
return n;
}
void *MemPool::Alloc()
{
allocated++;
if (freeList) {
recycled++;
FreeNode *tmp= freeList;
freeList= freeList->next;
return (void*)tmp;
}
if (lastIndex >= cMemPoolSize) { // need new chunk
chunks= new Chunk(chunks, chunkSize);
lastIndex= 0;
}
return (void*) &chunks->storage[lastIndex++ * objSize];
}
void MemPool::Free(void *op)
{
if (storageFreeHook)
storageFreeHook(storageFreeHookData, op, objSize);
for (Chunk *p= chunks; p; p= p->next) {
if (op >= (void*)p->storage && op < (void*)(p->storage + chunkSize)) {
memset(op, 0, objSize);
FreeNode *fn= (FreeNode*)op;
fn->next= freeList;
freeList= fn;
freed++;
return;
}
}
fprintf(stderr, "Fatal in MemPool::Free: object to delete not found in pool %d\n", objSize);
fflush(stderr);
CLib::Abort();
}
//---- Storage -----------------------------------------------------------------
void* operator new(size_t size)
{
register int *sp;
if (size < 0) {
fprintf(stderr, "Fatal in operator new: size < 0\n");
fflush(stderr);
CLib::Abort();
}
#ifdef MEM_MAGIC
sp= (int*) CLib::CAlloc(size + sizeof(int) + sizeof(char), sizeof(char));
#else
sp= (int*) CLib::CAlloc(size + sizeof(int), sizeof(char));
#endif
if (sp == 0) {
fprintf(stderr, "Fatal in operator new: storage exhausted\n");
fflush(stderr);
CLib::Abort();
}
sp[0]= size;
#ifdef MEM_MAGIC
*((char*)sp+size+sizeof(int))= MEM_MAGIC;
#endif
EnterStat(size, &sp[1]);
return CheckObjPtr("new", &sp[1]);
}
void operator delete(void* ptr)
{
Storage_lastobj= Storage_lastobjend= 0;
Storage_proto= FALSE;
if (ptr) {
(void) CheckObjPtr("free", ptr);
if (!died && FreeFromPool(ptr))
return;
int size= storage_size((char*)ptr);
if (size < 0 || size > maxA) {
fprintf(stderr, "Fatal in operator delete: unreasonable size (%d)\n", size);
fflush(stderr);
CLib::Abort();
}
RemoveStat(size, ptr);
if (storageFreeHook)
storageFreeHook(storageFreeHookData, ptr, size);
ptr= (char*)ptr - sizeof(int);
size+=sizeof(int);
#ifdef MEM_MAGIC
if (*((char*)ptr+size) != MEM_MAGIC) {
fprintf(stderr, "Fatal in operator delete: storage area overwritten\n");
fflush(stderr);
CLib::Abort();
}
size+= sizeof(char);
#endif
memset(ptr, 0, size);
CLib::ErrNo= 0;
CLib::Free((char*) ptr);
if (CLib::ErrNo != 0) {
perror("operator delete");
CLib::Abort();
}
}
}
void *Realloc(void *vp, size_t size)
{
if (vp == 0)
return new char[size];
int oldsize= storage_size((char*)vp);
if (size > oldsize) {
int *sp, sz= size;
char *ptr= (char*)vp, *cp;
RemoveStat(oldsize, vp);
#ifdef MEM_MAGIC
sz+= sizeof(char);
#endif
sp= (int*) CLib::ReAlloc((char*) (ptr - sizeof(int)), sz+sizeof(int));
cp= (char*) &sp[1];
EnterStat(size, &sp[1]);
#ifdef MEM_MAGIC
if (cp[oldsize] != MEM_MAGIC) {
fprintf(stderr, "Fatal in Realloc: storage area overwritten\n");
fflush(stderr);
CLib::Abort();
}
*((char*)sp+size+sizeof(int))= MEM_MAGIC;
#endif
memset(&cp[oldsize], 0, size-oldsize);
sp[0]= size;
return CheckObjPtr("Realloc", cp);
}
return vp;
}
void *Storage::Alloc(size_t sz)
{
return new char[sz];
}
void *Storage::Alloc(size_t sz, const char*, int)
{
return new char[sz];
}
void Storage::Free(void *vp)
{
delete vp;
}
void *Storage::ChunkAlloc(size_t sz)
{
if (died || sz >= cObjMaxSize)
return (void*) new char[sz];
MemPool *mp= pools[sz];
if (mp == 0)
mp= pools[sz]= new MemPool(sz);
return CheckObjPtr("Storage::ChunkAlloc", mp->Alloc());
}
void Storage::ChunkFree(void *vp)
{
register int i;
register Chunk *p;
register MemPool *mp;
for (i= 0; i < cObjMaxSize; i++) {
if (mp= pools[i]) {
for (p= mp->chunks; p; p= p->next) {
if (vp >= (void*)p->storage
&& vp < (void*)(p->storage + mp->chunkSize)) {
mp->Free(vp);
return;
}
}
}
}
}
void *Storage::ObjectChunkAlloc(size_t sz)
{
if (died || sz >= cObjMaxSize)
return (void*) new char[sz];
MemPool *mp= pools[sz];
if (mp == 0)
mp= pools[sz]= new MemPool(sz);
return CheckObjPtr("Storage::ObjectChunkAlloc", mp->Alloc());
}
void Storage::ObjectChunkFree(void *vp)
{
delete vp;
}
void *Storage::ObjectAlloc(size_t sz)
{
Storage_proto= FALSE;
Storage_lastobj= (u_long) new char[sz];
Storage_lastobjend= Storage_lastobj + sz;
return (void*) Storage_lastobj;
}
void *Storage::ObjectAlloc(size_t sz, const char*, int)
{
Storage_proto= FALSE;
Storage_lastobj= (u_long) new char[sz];
Storage_lastobjend= Storage_lastobj + sz;
return (void*) Storage_lastobj;
}
void Storage::ObjectFree(void *vp)
{
delete vp;
}
void *Storage::ReAlloc(void *vp, size_t sz)
{
return ::Realloc(vp, sz);
}
void Storage::SetFreeHook(FreeHookFun fh, void *data)
{
storageFreeHook= fh;
storageFreeHookData= data;
}
void Storage::Statistics()
{
#ifdef MEM_STAT
MemPool *fsp;
if (!gMemStatistics)
return;
if (totalA == totalF) {
fprintf(stderr, "no garbage left (total: %d)\n", totalA);
return;
}
fprintf(stderr, "\n");
fprintf(stderr, "Mem statistics\n");
fprintf(stderr, "%7s%7s%7s%7s%7s%7s%7s%7s",
"size", "alloc", "free", "diff", "alloc", "recycl", "freed", "chunks\n");
fprintf(stderr, "=======================================================\n");
for (int i= 0; i < cObjMaxSize; i++) {
fsp= pools[i];
if (ASizes[i] != FSizes[i] || fsp)
fprintf(stderr, "%7d%7d%7d%7d", i, ASizes[i], FSizes[i],
ASizes[i]-FSizes[i]);
if (fsp)
fprintf(stderr, "%7d%7d%7d%7d", fsp->allocated,
fsp->recycled, fsp->freed, fsp->nchunks());
if (ASizes[i] != FSizes[i] || fsp)
fprintf(stderr, "\n");
}
if (totalA != totalF) {
fprintf(stderr, "-------------------------------------------------------\n");
fprintf(stderr, "total: %7d%7d%7d\n", totalA, totalF, totalA-totalF);
}
if (mem_size != -1) {
fprintf(stderr, "-------------------------------------------------------\n");
for (i= 0; i < tt; i++)
if (ttt[i])
fprintf(stderr, "block %d of size %d not freed\n", i, mem_size);
}
fprintf(stderr, "=======================================================\n");
fprintf(stderr, "\n");
fflush(stderr);
#endif
}
void Storage::EnableStatistics(int size, int ix)
{
#ifdef MEM_STAT
mem_size= size;
mem_ix= ix;
gMemStatistics= TRUE;
#endif
}
void Storage::FreeAll()
{
died= TRUE;
for (int i= 0; i < cObjMaxSize; i++)
SafeDelete(pools[i]);
Statistics();
}